package com.best.oasis.settlement.loginservice;

import java.security.Principal;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.encoding.ShaPasswordEncoder;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.security.userdetails.ldap.LdapUserDetailsImpl;
import org.springframework.stereotype.Service;

import com.best.oasis.settlement.common.entity.security.User;
import com.best.oasis.settlement.common.error.ErrorCode;
import com.best.oasis.settlement.common.vo.security.UserVO;
import com.best.oasis.settlement.dao.security.UserDao;
import com.best.oasis.settlement.service.base.BaseServiceImpl;
import com.best.oasis.settlement.service.base.BusinessException;
import com.best.oasis.settlement.service.security.UserService;

@Service
public class LoginServiceImpl extends BaseServiceImpl<User, UserVO, Long> implements LoginService {
	
    @Autowired 
    private UserDao userDao;
    @Autowired
	private AuthenticationManager authManager;
    @Autowired
    private ShaPasswordEncoder passwordEncoder;
    @Autowired 
    private UserService userService;
    
    @Override
    public void afterConstruct(){
        super.setBaseDao(userDao);
        super.setEntityClass(User.class);
        super.setEntityVOClass(UserVO.class);
    }
    /**
     * 
     * {@inheritDoc}
     */
    public Principal login(String username, String password) {
    	logger.info("user " + username + " start to login.");
    	username = StringUtils.trim(username);
    	password = StringUtils.trim(password);
    	
        try{
            Authentication authentication = this.authManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            LdapUserDetailsImpl ldapUserDetailsImpl ;
            User user = null;
            if(authentication.getPrincipal() instanceof LdapUserDetailsImpl){
                ldapUserDetailsImpl = (LdapUserDetailsImpl)authentication.getPrincipal();
                user = (User)userDao.loadUserByUsername(ldapUserDetailsImpl.getUsername());
                UsernamePasswordAuthenticationToken authToken = 
                    new UsernamePasswordAuthenticationToken(user, null, authentication.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }else{
                SecurityContextHolder.getContext().setAuthentication(authentication);
                logger.info("user " + username + " loginned through local DB.");
	        	
	        	logger.info("save user " + username + " password to local DB.");
	            user = (User)userDao.loadUserByUsername(username);
	        	savePasswordToLocalDB(user, password);
            }

            return authentication;
        }catch(UsernameNotFoundException e){
        	//用户名或密码错误,请重新输入！
        	UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null);
        	authentication.setDetails(ErrorCode.USER_NOT_EXIST);
        	return authentication;
        	//throw new BusinessException("","用户名或密码错误,请重新输入！");
        }catch(Exception e){
            throw new BusinessException("",e.getMessage());
        }
    }
    
    /**
     * 保存用户密码到本地数据库，这样下次验证就直接在本地验证，省得去LDAP验证。这样以来，万一LDAP挂了，大部分曾经
     * 登录过的用户还可以正常使用
     * @param user
     * @param password
     */
    private void savePasswordToLocalDB(User user, String password){
    	String shaPassword = passwordEncoder.encodePassword(password, null);
    	if(!shaPassword.equals(user.getPassword())){
    		UserVO vo = userService.get(user.getId());
    		vo.setPassword(shaPassword);
    		userService.update(vo);
    	}
    }

}
